﻿using Coldairarrow.Business;
using Coldairarrow.Entity;
using Coldairarrow.IBusiness;
using Coldairarrow.Util;
using EFCore.Sharding;
using Elasticsearch.Service;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using NSwag;
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Text.Json;
using System.Threading.Tasks;
using UEditor.Core;

namespace Coldairarrow.Api
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            _configuration = configuration;
            
        }
        public static IServiceScopeFactory ServiceScopeFactory { get; private set; }
        readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";//名字随便起
        private readonly IConfiguration _configuration;


        public void ConfigureServices(IServiceCollection services)
        {
            //services.AddScoped<TenantInfo>();
     
            services.Configure<EFCoreShardingOptions>(options => options.OnSaveChanges = OnSaveChanges);
            services.Configure<EFCoreShardingOptions>(options => options.EntityTypeBuilderFilter = tenantEntityTypeBuilderFilter);
            services.Configure<EFCoreShardingOptions>(options => options.GetDePartId = () =>
            {
                using (var scop = ServiceLocator.Instance.CreateScope())
                {
                    var tenantProvider = scop.ServiceProvider.GetService<ITenantProvider>();
                    return tenantProvider.GetDepartmentId();
                }
            });

            //--------------2023-1-11添加
            //初始化模型验证配置
            // services.UseMethodsModelParameters().UseMethodsGeneralParameters();
            //services.AddSingleton<IObjectModelValidator>(new NullObjectModelValidator());
            //

            services.AddFxServices();
            services.AddAutoMapper();
            //------2023-1-5------
            //注入SignalR实时通讯，默认用json传输
            services.AddSignalR();
            services.AddCors(options => options.AddPolicy(MyAllowSpecificOrigins,
                       builder =>
                       {
                           builder.SetIsOriginAllowed(origin => true)
                                  .AllowAnyMethod()
                                  .AllowAnyHeader()
                                  .AllowCredentials();
                       }));

            ////////////2023-8-4新增加
            //上传文件大小限制Kestrel设置
            //services.Configure<KestrelServerOptions>(options =>
            //{
            //    // Set the limit to 256 MB
            //    options.Limits.MaxRequestBodySize = 268435456;
            //});
            //上传文件大小限制IIS设置
            //services.Configure<IISServerOptions>(options =>
            //{
            //    options.MaxRequestBodySize = long.Parse(_configuration.GetSection("Kestrel").Value);
            //});

            //---ES全文检索
            services.AddSingleton<IEsClientProvider, EsClientProvider>();
            //---富文本
            services.AddUEditorService("ueditor.json", true);

            /////////////////////
            services.Configure<ApiBehaviorOptions>(options => options.SuppressModelStateInvalidFilter = true);
            services.AddControllers(options =>
            {
                options.Filters.Add<ValidFilterAttribute>();
                options.Filters.Add<GlobalExceptionFilter>();
             
            })
            .AddNewtonsoftJson(options =>
            {
                options.SerializerSettings.GetType().GetProperties().ForEach(aProperty =>
                {
                    var value = aProperty.GetValue(JsonExtention.DefaultJsonSetting);
                    aProperty.SetValue(options.SerializerSettings, value);
                });

            });

            services.AddHttpContextAccessor();
            if (_configuration.GetSection("UseSwagger").Value == "true")
            {
                //swagger
                services.AddOpenApiDocument(settings =>
                {
                    settings.AllowReferencesWithProperties = true;
                    settings.AddSecurity("身份认证Token", Enumerable.Empty<string>(), new OpenApiSecurityScheme()
                    {
                        Scheme = "bearer",
                        Description = "Authorization:Bearer {your JWT token}<br/><b>授权地址:/Base_Manage/Home/SubmitLogin</b>",
                        Name = "Authorization",
                        In = OpenApiSecurityApiKeyLocation.Header,
                        Type = OpenApiSecuritySchemeType.Http
                    });
                });
            }

    


            //jwt
            services.AddJwt(_configuration);
            //---------------2023-1-11添加
            services.AddHttpClient();
  
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider)
        {
            
            DefaultFilesOptions defaultfilesoptions = new DefaultFilesOptions();
            defaultfilesoptions.DefaultFileNames.Clear();
            defaultfilesoptions.DefaultFileNames.Add("index.html");
            //允许body重用
            app.Use(next => context =>
            {
                context.Request.EnableBuffering();
                return next(context);
            });
            app.UseDefaultFiles(defaultfilesoptions);
            //跨域
            app.UseCors(MyAllowSpecificOrigins);
            app.UseMiddleware<RequestBodyMiddleware>()
            .UseMiddleware<RequestLogMiddleware>()
            .UseDeveloperExceptionPage()
            .UseStaticFiles(new StaticFileOptions
            {
                ServeUnknownFileTypes = true,
                DefaultContentType = "application/octet-stream",
                ///////2023-8-4新增加
                //OnPrepareResponse = (c) =>
                //{
                //    c.Context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
                //}
                //////////
            })
            .UseRouting()
            .UseAuthentication()
            .UseAuthorization()
            .UseEndpoints(endpoints =>
            {
                endpoints.MapHub<MessageHub>("/MessageHub");
                endpoints.MapControllers();
            });

            if (_configuration.GetSection("UseSwagger").Value == "true")
            {
                app.UseOpenApi()//添加swagger生成api文档（默认路由文档 /swagger/v1/swagger.json）

           .UseSwaggerUi3(x => x.DocExpansion="list")//添加Swagger UI到请求管道中(默认路由: /swagger).
           ;
            }
            app.UseOutImg();
            ServiceLocator.Instance = app.ApplicationServices;
        }

        

        // /// <summary>
        // /// 新增实体时自动设置工厂id
        // /// </summary>
        Func<IServiceProvider, DbContext, Func<Task>, Task> OnSaveChanges = async (serviceProvider, context, func) =>
       {
           var FactoryId = "";
           using (var scop = serviceProvider.CreateScope())
           {
               var tenantProvider = scop.ServiceProvider.GetService<ITenantProvider>();
               FactoryId = tenantProvider.GetDepartmentId();
           }
           if (!string.IsNullOrEmpty(FactoryId))
           {
               context.ChangeTracker.DetectChanges();
               var entities = context.ChangeTracker.Entries().Where(e => (e.State == EntityState.Added || e.State == EntityState.Modified) && e.Entity is BaseEntity);
               string tenantIdFieldName = "FactoryId";
               foreach (var entity in entities)
               {
                   switch (entity.State)
                   {
                       // 自动设置租户Id
                       case EntityState.Added:
                           //2023.3.22添加
                           var tenantId = entity.Property(nameof(BaseEntity.FactoryId)).CurrentValue;
                           var currTenantId = FactoryId;
                           if (tenantId.IsNullOrEmpty() && !currTenantId.IsNullOrEmpty())
                               entity.Property(tenantIdFieldName).CurrentValue = currTenantId;
                           break;
                       // 排除租户Id
                       case EntityState.Modified:
                           entity.Property(tenantIdFieldName).IsModified = false;
                           break;
                   }
               }
           }
           await func.Invoke();
       };
        public static class ServiceLocator
        {
            public static IServiceProvider Instance { get; set; }
        }
        // ///// <summary>
        // ///// 配置部门全局过滤
        // ///// </summary>
        Action<EntityTypeBuilder> tenantEntityTypeBuilderFilter = (entityTypeBuilder) =>
       {
           var FactoryId = "";
           IMutableEntityType metadata = entityTypeBuilder.Metadata;
           using (var scop = ServiceLocator.Instance.CreateScope())
           {
               var tenantProvider = scop.ServiceProvider.GetService<ITenantProvider>();
               FactoryId = tenantProvider.GetDepartmentId();
           }

           if (!string.IsNullOrEmpty(FactoryId)&&FactoryId!="Admin" && typeof(BaseEntity).IsAssignableFrom(entityTypeBuilder.Metadata.ClrType))
           {
               var parameter = Expression.Parameter(entityTypeBuilder.Metadata.ClrType, "e");
               var body = Expression.Equal(
                   Expression.Call(typeof(EF), nameof(EF.Property), new[] { typeof(string) }, parameter, Expression.Constant("FactoryId")),
                   Expression.Constant(FactoryId));
             
               entityTypeBuilder.HasQueryFilter(Expression.Lambda(body, parameter));
           }
       };

       
    }
}
